package com.example.service.provider.controller;

import com.example.service.common.api.entity.ResponseResult;
import com.example.service.common.dto.FileTestDto;
import com.example.service.common.dto.TestDto;
import com.example.service.common.vo.TestVo;
import com.netflix.hystrix.contrib.javanica.annotation.DefaultProperties;
import com.netflix.hystrix.contrib.javanica.annotation.HystrixCommand;
import com.netflix.hystrix.contrib.javanica.annotation.HystrixProperty;
import org.springframework.http.MediaType;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.multipart.MultipartFile;

import java.time.LocalDate;

@RestController("Service1Controller")
@RequestMapping("/service1")
@DefaultProperties(commandProperties = {
    // 请求响应超时时间
    @HystrixProperty(name ="execution.isolation.thread.timeoutInMilliseconds",value = "1000"),
    // 开启断路器
    @HystrixProperty(name ="circuitBreaker.enabled",value = "true"),
    // 当快照时间窗口内的请求数达到指定阈值时，才有资格触发熔断器，否则即使其他条件达到了，也不会触发熔断
    @HystrixProperty(name ="circuitBreaker.requestVolumeThreshold",value = "3"),
    // 滑动窗口算法。指定时间(快照时间)内的所有请求将会被观察分析统计，单位毫秒
    @HystrixProperty(name ="circuitBreaker.sleepWindowInMilliseconds",value = "10000"),
    // 当快照时间窗口内的请求失败所占的比例达到50%时，就会将熔断器打开
    @HystrixProperty(name ="circuitBreaker.errorThresholdPercentage",value = "1")
})
public class Service1Controller {

    @HystrixCommand(fallbackMethod = "pathAndBodyArgPostHystrixHystrixFallBack",
            commandProperties = {
                // 信号量SEMAPHORE策略:在调用线程上执行HystrixCommand.run()方法，并使用"信号量"允许计数来限制并发执行。
                @HystrixProperty(name ="execution.isolation.strategy",value = "SEMAPHORE"),
                // 信号量SEMAPHORE策略，当前服务器最多只能并发处理20个请求，超过则服务降级
                @HystrixProperty(name ="execution.isolation.semaphore.maxConcurrentRequests",value = "20"),
            }
    )
    @PostMapping("/post/pathAndBodyArg/hystrix/{name}")
    public ResponseResult<TestVo> pathAndBodyArgPostHystrix(@PathVariable("name")String name,
                                                            TestDto dto) throws InterruptedException {

        TestVo testVo = new TestVo();
        testVo.setName(name);
        int random = (int) (Math.random()*Integer.MAX_VALUE);
        System.out.println(random);
        testVo.setAge(random);
        testVo.setList(dto.getList());
        testVo.setLocalDate(dto.getLocalDate());
        return ResponseResult.success(testVo);
    }

    @HystrixCommand(defaultFallback = "noArgGetHystrixHystrixFallBack",
        commandProperties = {
            // 线程池THREAD：在单独的线程上执行HystrixCommand.run()方法，并使用线程池大小限制并发执行。
            @HystrixProperty(name ="execution.isolation.strategy",value = "THREAD")
        },threadPoolProperties = {
            // 线程池中最多只能有3个线程正在并发处理
            @HystrixProperty(name ="coreSize",value = "3"),
            // 线程队列中最多只能存放未处理的并发线程数。如果当请求超过coreSize+maxQueueSize时，后面的请求就都会被拒绝，
            // 即会触发服务降级。注意得不配置maximumSize
            @HystrixProperty(name ="maxQueueSize",value = "5"),
            // 当线程池中线程个数(即请求数)达到queueSizeRejectionThreshold时，就会拒绝请求，触发服务降级
            @HystrixProperty(name ="queueSizeRejectionThreshold",value = "10"),
    })
    @GetMapping("/get/noArg/hystrix")
    public ResponseResult<TestVo> noArgGetHystrix() throws InterruptedException {
        Thread.sleep(10000);
        return ResponseResult.success(TestVo.defaultCreate());
    }


    @GetMapping("/get/noArg")
    public ResponseResult<TestVo> noArgGet(){
        return ResponseResult.success(TestVo.defaultCreate());
    }

    @GetMapping("/get/pathArg/{name}/{date}")
    public ResponseResult<TestVo> pathArgGet(@PathVariable("name")String name, @PathVariable("date")LocalDate date){
        return ResponseResult.success(TestVo.defaultCreate().setName(name).setLocalDate(date));
    }

    @PostMapping(value = "/post/pathAndBodyArg/{name}/{date}",consumes = MediaType.APPLICATION_JSON_VALUE)
    public ResponseResult<TestVo> pathAndBodyArgPost(@PathVariable("name")String name, @PathVariable("date")LocalDate date,
                                 @RequestBody TestDto dto){
        TestVo testVo = new TestVo();
        testVo.setName(name)
                .setLocalDate(date)
                .setAge(Math.toIntExact(dto.getAge()))
                .setList(dto.getList());
        return ResponseResult.success(testVo);
    }

    @PostMapping("/post/file/{e}")
    public ResponseResult<TestVo> pathAndBodyArgAndFileArgPost(@PathVariable("e") String e,
                                                               FileTestDto fileTestDto){
        TestVo testVo = new TestVo();
        if(fileTestDto.getMultipartFile()!=null){
            testVo.setName(fileTestDto.getMultipartFile().getName());
            System.out.println();
        }
        if(fileTestDto.getFileList()!=null){
            for(MultipartFile file:fileTestDto.getFileList()){
                testVo.getList().add(file.getName());
            }
        }
        testVo.setLocalDate(fileTestDto.getLocalDate())
                .setAge(Math.toIntExact(fileTestDto.getAge()))
                .setList(fileTestDto.getList());
        testVo.getList().add(e);
        return ResponseResult.success(testVo);
    }

    @PutMapping("/put/pathAndBodyArg/{name}/{date}")
    public TestVo pathAndBodyArgPut(@PathVariable("name")String name, @PathVariable("date")LocalDate date,
                                 @RequestBody TestDto dto){
        TestVo testVo = new TestVo();
        testVo.setName(name)
                .setLocalDate(date)
                .setAge(Math.toIntExact(dto.getAge()))
                .setList(dto.getList());
        return testVo;
    }


    public ResponseResult<TestVo> pathAndBodyArgPostHystrixHystrixFallBack(String name, TestDto dto,Throwable t){
        return noArgGetHystrixHystrixFallBack(t);
    }

    public ResponseResult<TestVo> noArgGetHystrixHystrixFallBack(Throwable t){
        System.out.println("服务降级"+t.getMessage());
        return ResponseResult.success(new TestVo().setName("服务降级"));
    }
}
